package com.hj.javaweb.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.Map;

@Slf4j
public class RestTemplateUtil {

    /**
     * 将请求原样转发到目标地址，并返回结果
     *
     * @param request      请求对象
     * @param url          目标地址
     * @param restTemplate RestTemplate对象
     * @return
     */
    public static ResponseEntity<String> getStringResponseEntity(HttpServletRequest request, String url, RestTemplate restTemplate) throws IOException {
        // 构造请求头
        HttpHeaders headers = new HttpHeaders();
        HttpMethod httpMethod = HttpMethod.valueOf(request.getMethod());
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headers.add(headerName, request.getHeader(headerName));
        }

        // 构造请求体，分格式处理请求体
        HttpEntity<?> httpEntity = buildHttpEntityByContentType(request, headers, httpMethod);

        // 发送请求
        try{
            ResponseEntity<byte[]> response = restTemplate.exchange(url, httpMethod, httpEntity, byte[].class);
            
            // 手动解析响应
            String responseBody = new String(response.getBody(), StandardCharsets.UTF_8);
            
            // 原样返回结果
            return ResponseEntity.status(response.getStatusCode())
                    .headers(response.getHeaders())
                    .body(responseBody);
        }catch (Exception e){
            log.error("请求目标地址失败：{}", e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
        }
    }

    private static HttpEntity<?> buildHttpEntityByContentType(HttpServletRequest request, HttpHeaders headers, HttpMethod httpMethod) throws IOException {
        // GET/DELETE 无请求体
        if (HttpMethod.GET.equals(httpMethod) || HttpMethod.DELETE.equals(httpMethod)) {
            return new HttpEntity<>(headers);
        }

        String contentType = request.getContentType();
        if (contentType == null) {
            // 无 Content-Type：按字节流直接转发
            byte[] bytes = StreamUtils.copyToByteArray(request.getInputStream());
            return new HttpEntity<>(bytes, headers);
        }

        // multipart/form-data（表单/文件上传）
        if (contentType.startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)) {
            return buildMultipartFormDataEntity(request, headers);
        }

        // JSON 格式（application/json）
        if (contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
            return buildJsonEntity(request, headers);
        }

        // 其他格式（文本，表单，urlencoded等）按字节流转发
        byte[] bytes = StreamUtils.copyToByteArray(request.getInputStream());
        headers.setContentType(MediaType.parseMediaType(contentType));
        return new HttpEntity<>(bytes, headers);
    }

    private static HttpEntity<?> buildJsonEntity(HttpServletRequest request, HttpHeaders headers) throws IOException {
        // 读取原始json字节流，直接转发（避免String类型导致的双重序列化）
        byte[] bytes = StreamUtils.copyToByteArray(request.getInputStream());
        headers.setContentType(MediaType.APPLICATION_JSON);
        return new HttpEntity<>(bytes, headers);
    }

    private static HttpEntity<?> buildMultipartFormDataEntity(HttpServletRequest request, HttpHeaders headers) throws IOException {
        // 转换为 Multipart 请求对象，方便解析表单字段和文件
        StandardMultipartHttpServletRequest multipartRequest = new StandardMultipartHttpServletRequest(request);
        MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();

        // 添加普通表单字段
        Map<String, String[]> parameterMap = multipartRequest.getParameterMap();
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String key = entry.getKey();
            for (String value : entry.getValue()) {
                formData.add(key, value);
            }
        }

        // 添加文件
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entry : fileMap.entrySet()) {
            String key = entry.getKey();
            MultipartFile file = entry.getValue();
            if (!file.isEmpty()) {
                // 构建文件请求体（包含文件字节、文件名、文件类型）
                HttpHeaders fileHeaders = new HttpHeaders();
                fileHeaders.setContentType(MediaType.parseMediaType(file.getContentType()));
                fileHeaders.setContentDispositionFormData(key, file.getOriginalFilename());
                HttpEntity<byte[]> httpEntity = new HttpEntity<>(file.getBytes(), fileHeaders);
                formData.add(key, httpEntity);
            }
        }

        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        return new HttpEntity<>(formData, headers);
    }
}
